<script>
import { defineComponent, ref, watchEffect, watch, computed, onMounted, onUnmounted } from 'vue'
import { createNamespace, transformSize, transformStyleSize, roundNumber, padNumber } from '../utils'

export default defineComponent({
  name: createNamespace('CountTo')[0],
  options: {
    // https://uniapp.dcloud.io/matter.html#mp
    virtualHost: true
  },
  emits: ['finish'],
  props: {
    startNum: {
      type: [Number, String],
      default: 0
    },
    endNum: {
      type: [Number, String],
      default: 0
    },
    step: {
      type: [Number, String],
      default: 1
    },
    // 数字切换的时间 单位为秒
    speed: {
      type: [Number, String],
      default: 1
    },
    // 数字切换时动画的时间 单位为秒
    duration: [String, Number],
    color: String,
    bg: String,
    textSize: [String, Number],
    bold: [String, Number],
    height: [String, Number],
    width: [String, Number],
    symbolWidth: [String, Number],
    radius: [String, Number],
    marginRight: [Number, String],
    lineHeight: [Number, String]
  },
  setup(props, { emit }) {
    const numList = ref([0])
    const startVal = ref(props.startNum)
    const endVal = ref(props.endNum)
    let decimalLength = 0
    let isMinus = false
    let timer = null

    // 初始化numList
    const initNumList = (start, end) => {
      start = start.split('.')
      end = end.split('.')
      const step = String(props.step).split('.')
      let startNum = JSON.parse(JSON.stringify(start))
      const maxIntegerLength = Math.max(start[0]?.length || 0, end[0]?.length || 0, step[0]?.length || 0),
        maxDecimalLength = Math.max(start[1]?.length || 0, end[1]?.length || 0, step[1]?.length || 0)
      decimalLength = maxDecimalLength
      if (start[0]?.length < maxIntegerLength) startNum[0] = padNumber(startNum[0], maxIntegerLength)
      if (!start[1] && maxDecimalLength !== 0) {
        startNum[1] = padNumber(0, maxDecimalLength)
      } else if (start[1]?.length < maxDecimalLength) {
        startNum[1] = padNumber(startNum[1], maxDecimalLength, { right: true })
      }
      return startNum.length === 2 ? startNum.join('.').split('') : startNum.join('').split('')
    }

    const translateList = computed(() => {
      const translate = []
      numList.value.forEach((num) => translate.push(`transform: translate(0, -${num * 10}%)`))
      return translate
    })

    const theStyle = computed(() => {
      const {
        bg,
        textSize,
        bold,
        color,
        height,
        radius,
        width,
        duration,
        marginRight,
        symbolWidth,
        lineHeight
      } = props
      let s = ''
      if (bg) s += `--fan-count-to-bg: ${bg};`
      if (textSize)
        s += `--fan-count-to-size: ${transformSize(textSize)};--fan-count-to-height: ${transformSize(
          parseFloat(textSize) * 1.4
        )};`
      if (bold) s += `--fan-count-to-weight: ${bold};`
      if (color) s += `--fan-count-to-color: ${color};`
      if (radius) s += `--fan-count-to-radius: ${transformSize(radius)};`
      if (height) s += `--fan-count-to-height: ${transformSize(height)};`
      if (width) s += `--fan-count-to-width: ${transformSize(width)};`
      if (marginRight) s += `--fan-count-to-margin: ${transformSize(marginRight)};`
      if (duration) s += `--fan-count-to-duration:${duration}s;`
      if (symbolWidth) s += `--fan-count-to-symbol-width:${transformSize(symbolWidth)}`
      if (lineHeight) s += `--fan-count-to-line-height: ${transformSize(lineHeight)}`

      return transformStyleSize(s)
    })

    watchEffect(() => {
      const start = String(startVal.value),
        end = String(endVal.value)
      if (startVal.value > endVal.value) isMinus = true
      numList.value = initNumList(start, end)
    })

    const onFinish = () => {
      clearInterval(timer)
      timer = null
      emit('finish')
    }
    const increaseNumber = () => {
      const { step, speed } = props
      if (Number(startVal.value) === Number(endVal.value)) return
      timer = setInterval(() => {
        if (isMinus) {
          startVal.value = roundNumber(Number(startVal.value) - Number(step), decimalLength)
          if (Number(startVal.value) <= Number(endVal.value)) return onFinish()
        } else {
          startVal.value = roundNumber(Number(startVal.value) + Number(step), decimalLength)
          if (Number(startVal.value) >= Number(endVal.value)) return onFinish()
        }
      }, Number(speed) * 1000)
    }

    watch(
      () => props.endNum,
      (val) => (endVal.value = val),
      { immediate: true }
    )
    watch(
      () => props.startNum,
      (val) => (startVal.value = val),
      { immediate: true }
    )
    onMounted(() => increaseNumber())
    onUnmounted(() => clearInterval(timer))

    return {
      theStyle,
      translateList,
      numList
    }
  }
})
</script>

<template>
  <div class="count-to" :style="theStyle">
    <div class="fan-flex fan-align-center">
      <div class="count-to_num" :class="[isNaN(item) ? 'number_symbol' : 'number-item']" v-for="(item, i) in numList"
        :key="i">
        <span v-if="!isNaN(item)" class="number-item_num" :style="translateList[i]">
          <span class="number-item_num_box">
            <span class="number-item_num__txt">0123456789</span>
          </span>
        </span>
        <span v-else>{{ item }}</span>
      </div>
    </div>
  </div>
</template>

<style lang="less">
.count-to {
  --fan-count-to-color: var(--fan-color2-fg);
  --fan-count-to-weight: var(--fan-text-mbold);
  --fan-count-to-size: inherit;
  --fan-count-to-bg: var(--fan-primary-color);
  --fan-count-to-radius: 0;
  --fan-count-to-margin: 5px;
  --fan-count-to-duration: 0.3s;
  --fan-count-to-height: 26px;
  --fan-count-to-width: 22px;
  --fan-count-to-line-height: var(--fan-count-to-height);
  --fan-count-to-symbol-width: var(--fan-count-to-width);

  display: inline-block;
  overflow: hidden;
  color: var(--fan-count-to-color);
  font-weight: var(--fan-count-to-weight);
  font-size: var(--fan-count-to-size);

  &_num {
    background: var(--fan-count-to-bg);
    margin-right: var(--fan-count-to-margin);
    width: var(--fan-count-to-width);
    height: var(--fan-count-to-height);
    border-radius: var(--fan-count-to-radius);
    text-align: center;
    overflow: hidden;

    &:last-child {
      margin-right: 0;
    }

    &.number_symbol {
      width: var(--fan-count-to-symbol-width);
    }

    &.number-item {
      .number-item_num {
        display: inline-block;
        width: 100%;
        transform: translate(0, 0);
        transition: var(--fan-count-to-duration) ease-in-out;

        &_box {
          word-break: break-all;
          display: inline-block;
          width: min-content;
        }

        &__txt {
          display: block;
          width: 100%;
          height: 100%;
          line-height: var(--fan-count-to-line-height);
        }
      }
    }
  }
}
</style>